/**
 * 1. 绑定resolve reject 的this
 * 2. 状态不可变
 * 3. resolve reject 以第一次为准 
 * 4. throw 执行reject
 */
class MyPromise {
  /**
   * 
   * @param {*} executor 传进来的函数
   */
  constructor(executor) {
    this.initValue()
    this.initBind()//1
    //4
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }

  }
  initValue() {
    this.State = 'pending'
    this.result = null
    this.onFulfilledCallBacks = []
    this.onRejectedCallBacks = []
  }
  /**
   * 防止运行环境改变，resolve-this改变
   */
  initBind() {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }
  /**
   * 要求pending=>fulfilled
   * 只改变一次
   * @param {*} value 成功是传进的值
   */
  resolve(value) {
    if (this.State !== 'pending') return //只改变一次 3,2
    this.State = 'fulfilled'
    this.result = value
    //通知then 回调
    while (this.onFulfilledCallBacks.length) {
      this.onFulfilledCallBacks.pop()()
    }
  }
  reject(reason) {
    if (this.State !== 'pending') return //只改变一次
    this.State = 'rejected'
    this.result = reason
    while (this.onRejectedCallBacks.length) {
      this.onRejectedCallBacks.pop()()
    }
  }
  /**
   * 1. 接受两个回调函数
   * 2. 定时器(异步执行)
   * 3. 链式调用
   * 4. then 可以被同一个promise调用多次
   * 5. 微任务
   * @param {fun} onFulfilled 成功回调
   * @param {fun} onRejected  失败回调
   */
  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val//简写参数判断
    onRejected = typeof onRejected === 'function' ? onRejected : reason => reason
    const thenPromise = new MyPromise((resolve, reject) => {

      /**
       * then 执行then 拿到他的值给下一个then使用//成功 或失败时候调用啊
       * @param {*} callback then 的回调函数
       */
      const resolvePromise = callback => {//绑定的是外部
        setTimeout(() => {
          //console.log(this)//this上一个Promise
          try {
            let callbackResult = callback(this.result)
            if (callbackResult instanceof MyPromise) {
              //执行结果就是MyPromise
              callbackResult.then(resolve, reject)// 等这个Promise自己决定成功还是失败
            } else {
              //直接就是成功的
              resolve(callbackResult)
            }
          } catch (error) {
            //回调执行失败
            reject(error)
          }
        })
      }
      if (this.State === 'fulfilled') {
        resolvePromise(onFulfilled)
      }
      if (this.State === 'rejected') {
        resolvePromise(onRejected)
      }
      if (this.State === 'pending') {
        //缓存回调 先进先出
        this.onFulfilledCallBacks.unshift(resolvePromise.bind(this, onFulfilled))
        this.onRejectedCallBacks.unshift(resolvePromise.bind(this, onRejected))
      }

    })
    return thenPromise//链式调用
  }

  /**
   *  相当于then(null,onReject)
   * @param {*} onRejected 
   * @returns 
   */
  catch(onRejected) {
    return this.then(null, onRejected);
  }
  /**
   * 指定不管 Promise 对象最后状态如何 
   * 回调函数不接受任何参数
   * 总是会返回原来的值
   * 返回的是一个
   */
  finnaly(callback) {
    return this.then(value => {
      MyPromise.resolve(callback()).then(() => value)
    }, reason => {
      MyPromise.reject(callback()).then(() => { throw reason })
    })
  }

  /**
   * 静态 resolve 把一个value 变成Promise
   * @param {any} 
   * 1. 参数是Promise 直接返回就是
   * 2. new Promise 包装一下
   */
  static resolve(value) {
    if (value && typeof value === 'object' && value instanceof MyPromise) {
      return value
    }
    return new MyPromise((resolve, reject) => {
      resolve(value)
    })
  }
  /**
   * 返回一个新的 Promise 实例，该实例的状态为rejected
   * @param {*} value 
   */
  static reject(value) {
    return new MyPromise((resolve, reject) => {
      reject(value)
    })
  }

  /**
   * 所有成功为成功,有错拒绝
   * @param {*} promiseArrs promise数组
   */
  static all(promiseArrs) {
    let res = []//promise数组执行结果
    let index = 0;
    return new MyPromise(resolve, reject => {
      if (promiseArrs.length) resolve([])
      promiseArrs.forEach((p, i) => {
        //先包一层 防止数组中有不是promise
        MyPromise.resolve(p).then(
          val => {
            index++;
            res[i] = val
            if (index == promiseArrs.length) {
              resolve(res)
            }
          },
          reason => {
            reject(reason)
          }
        )
      });
    })
  }

  /**
   * 返回第一个成功或者拒绝
   * @param {*} promiseArrs 
   * @returns 
   */
  static race(promiseArrs) {
    return new MyPromise(resolve, reject => {
      if (promiseArrs.length) resolve([])
      promiseArrs.forEach((p) => {
        //先包一层 防止数组中有不是promise
        MyPromise.resolve(p).then(
          val => {
            resolve(val)
          },
          reason => {
            reject(reason)
          }
        )
      });
    })
  }

  /**
   * 一组异步操作都结束了，不管每一个操作是成功还是失败，再进行下一步操作
   * @param {*} promiseArrs 
   */
  static AllSettled(promiseArrs){
    let res = []//promise数组执行结果
    let index = 0;
    return new MyPromise(resolve, reject => {
      if (promiseArrs.length) resolve([])

      const fn = (status,val,i)=>{
        res[i] = {
          status,val
        }
        index++;
        if(index==promiseArrs.length){
          resolve(res)
        }
      }

      promiseArrs.forEach((p, i) => {
        //先包一层 防止数组中有不是promise
        MyPromise.resolve(p).then(
          val => {
            fn("fulfilled",val,i)
          },reason=>{
            fn("rejected",reason,i)
          }
        )
      });
    })
  }

  /**
   * all 相反 有成功就成功
   * @param {*} promiseArrs 
   */
  static any(promiseArrs){
    let index = 0;
    let res = []
    return new MyPromise((resolve,reject)=>{
      if (promiseArrs.length) resolve([])
      promiseArrs.forEach((p,i)=>{
        MyPromise.resolve(p).then(
          val=>{
            resolve(val)
          },reason=>{
            index++;
            res[i] = reason
            if(index==promiseArrs.length)
            {
              reject(res)
            }
          }
        )
      })
    })
  }
}

/**
 * 测试
 */
function test1() {
  console.log("test start")
  let p0 = new MyPromise((resolve, reject) => {
    console.log(1)
    setTimeout(resolve(233), 1000)
    //resolve(233)
    //reject('err')
  })
  // p0.then(res => {
  //     console.log(res, "then1")
  // })
  p0.then(res => {
    console.log(res, 'then2')
    return 'then3'
  }).then(res => {
    console.log(res)
  })
  console.log("test end?")
  MyPromise.resolve(34).then(res => {
    console.log(res)
  })
}
test1()

// let p1 = new Promise((resolve,reject)=>{
//     console.log('1')
//     resolve(23)
// })
// p1.then(res=>{
//     console.log('then1' + res)
// })
// p1.then(res=>{
//     console.log('then2' + res)
// })
MyPromise.deferred = function () {
  var result = {};
  result.promise = new MyPromise(function (resolve, reject) {
    result.resolve = resolve;
    result.reject = reject;
  });

  return result;
}
module.exports = MyPromise;
